﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RWLibrary.Logic.BooleanExpression;

namespace RWLibrary.Logic
{
    public class State
    {
        public State(World world, int state = 0)
        {
            s = state;
            w = world;
        }

        public State(State old)
        {
            s = old.s;
            w = old.w;
        }

        private int s;
        private World w;

        private bool GetValue(int position)
        {
            return ((1 << position) & s) > 0;
        }

        public int CalculateHammingDistance(State other)
        {
            int val = s ^ other.s;
            int dist = 0;
            while (val>0)
            {
                ++dist;
                val &= val - 1;
            }
            return dist;
        }

        public bool this[string fluentName]
        {
            get { return GetValue(w.FluentPosition(fluentName)); }
            set
            {
                int mask = (1 << w.FluentPosition(fluentName));
                s &= (~mask);
                if (value)
                    s |= mask;
            }
        }

        /// <summary>
        /// Zwraca ten stan jako koniunkcja fluentów prawdziwych w tym stanie i zaprzeczeń fluentów nie prawdziwych (tak ze ta wyrazenie spelnia tylko i wylacznie ten state)
        /// </summary>
        /// <returns></returns>
        public IBooleanExpression stateToExpression()
        {
            IBooleanExpression result = new Truth();
            for (int i = 0; i < w.FluentCount; ++i)
            {
                bool value = this.GetValue(i);
                IBooleanExpression fluent= new Fluent(w.FluentName(i));
                if(!value)
                    fluent = new Negation(fluent);
                result = new And(result, fluent);
            }
            return result;
        }

        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();

            sb.AppendFormat("{0}{1}", GetValue(0) ? "" : "!", w.FluentName(0));
            for (int i = 1; i < w.FluentCount; i++)
            {
                sb.AppendFormat(", {0}{1}", GetValue(i) ? "" : "!", w.FluentName(i));
            }
            return sb.ToString();
        }

        public override bool Equals(object obj)
        {
            State other = obj as State;
            if (other == null) return false;
            return other.s == this.s;
        }

        public override int GetHashCode()
        {
            return this.s;
        }
    }
}
